#include "ExLobbyAvatarGameMgr.h"
#include <AtlasBase.h>
#include <AtlasCommon.h>
#include <AtlasServer.h>

#include "ExLobbyAvatarNode.h"
#include "ExLobbyCommon.h"


#define MAX_ROOM_NUM 200

//#define ZDEBUG(info) \
//		char szTmp[100];\
//		DWORD dwThread = GetCurrentThreadId();\
//		sprintf(szTmp, "%s thread:%d %s\n", __FUNCTION__, dwThread, info);\
//		OutputDebugString(szTmp);

//#define ZDEBUG(info)  while(0) {}

namespace Atlas
{
	static Atlas::CObjectManager<CRoomInfo, MAX_ROOM_NUM> _global_room_object_manager(&CRoomInfo::GetNNDX);
	typedef std::map<_U64, CRoomInfo*> ROOM_STORAGE;
	static ROOM_STORAGE _global_rooms;

	template<>
	CRoomInfo* CObjectLocker<CRoomInfo>::Lock(_U64 ndx)
	{
		return _global_room_object_manager.Lock(ndx);
	}

	template<>
	void CObjectLocker<CRoomInfo>::Unlock(_U64 ndx)
	{
		CRoomInfo* pRoom = _global_room_object_manager.GetObject(ndx);
		if(pRoom && pRoom->NeedDelete()) 
		{
			delete pRoom;
		}
		_global_room_object_manager.Unlock(ndx);
	}

	CRoomInfo::CRoomInfo(const ROOM_INFO& RoomInfo, _U64 nndx)
	{
		m_RoomInfo = RoomInfo;
		m_nndx = nndx;
		m_bIsExit = false;
		_global_room_object_manager.BindObject(nndx, this);
		_global_rooms[nndx] = this;
	}

	CRoomInfo::~CRoomInfo()
	{
		if(NeedDelete())
		{
			_global_rooms.erase(m_nndx);
		}
		else
		{
			
		}

		_global_room_object_manager.UnbindObject(m_nndx, this);
	}
	
	_U64 CRoomInfo::GetNNDX()
	{
		return m_nndx;
	}

	ROOM_INFO& CRoomInfo::GetRoomInfo()
	{
		return m_RoomInfo;
	}

	bool CRoomInfo::NeedDelete()
	{
		return m_bIsExit;
	}

	void CRoomInfo::AddClient(CExLobbyAvatarNodeClient* pClient)
	{
		m_SetClient.insert(pClient);
		pClient->SetRoomID(m_nndx);	
	}

	void CRoomInfo::SetExistState(bool bIsExist)
	{
		m_bIsExit = bIsExist;
	}

	std::set<CExLobbyAvatarNodeClient*>& CRoomInfo::GetClients()
	{
		return m_SetClient;
	}
	
	void CRoomInfo::DelClient(CExLobbyAvatarNodeClient* pClient)
	{
		std::set<CExLobbyAvatarNodeClient*>::iterator it = m_SetClient.find(pClient);
		if(it != m_SetClient.end())
		{
			m_SetClient.erase(it);
		}

		pClient->SetRoomID(ROOM_ID_INVAILD);

		if(m_SetClient.empty())
		{
			SetExistState(true);
		}
	}

	GameMgr::GameMgr()
	{
		A_MUTEX_INIT(&m_RoomLock);
	}

	GameMgr::~GameMgr()
	{
		//A_MUTEX_LOCK(&m_RoomLock);
		//ROOM_STORAGE::iterator it;
		//for(it = _global_rooms.begin(); it != _global_rooms.end(); )
		//{
		//	CRoomInfo* pRoom = _global_room_object_manager.Lock(it->first);
		//	if(pRoom)
		//	{
		//		delete pRoom;
		//	}

		//	_global_room_object_manager.Unlock(it->first);
		//	it = _global_rooms.erase(it);
		//}

		//A_MUTEX_UNLOCK(&m_RoomLock);

		A_MUTEX_DESTROY(&m_RoomLock);
	}

	void GameMgr::ListRoom(CExLobbyAvatarNodeClient* pClient, _U64 id)
	{
		//ZDEBUG("")
		A_MUTEX_LOCK(&m_RoomLock);
		ROOM_INFO list[MAX_ROOM_LIST_LEN];
		_U32 count = 0;

		ROOM_STORAGE::iterator it = _global_rooms.begin();

		for(_U64 i = id; i > 0; --i)
		{
			if(it != _global_rooms.end())
			{
				++it;
			}
		}
		
		for(; it != _global_rooms.end() && count < MAX_ROOM_LIST_LEN; ++it, ++count)
		{
			list[count] = it->second->GetRoomInfo();
		}

		A_MUTEX_UNLOCK(&m_RoomLock);
		pClient->Lobby.ListRoomResult(list, count);
	}

	void GameMgr::EnterRoom( CExLobbyAvatarNodeClient* pClient, _U64 id )
	{
		//have been in room
		if(pClient->GetRoomID() != ROOM_ID_INVAILD)
		{
			pClient->Lobby.EnterRoomResult(RET_CODE_FAILED);
			return;
		}

		Atlas::CObjectLocker<Atlas::CRoomInfo> Locker(id);
		CRoomInfo* pRoom = Locker.GetObject();
		if(!pRoom)
		{
			pClient->Lobby.EnterRoomResult(RET_CODE_FAILED);
			return;
		}

		pRoom->AddClient(pClient);
		pClient->Lobby.EnterRoomResult(RET_CODE_SUCC);

		//char szInfo[100];
		//sprintf(szInfo, "%p room:%u", pClient, pClient->GetRoomID());
		//ZDEBUG(szInfo);
	}

	void GameMgr::LeaveRoom( CExLobbyAvatarNodeClient* pClient )
	{
		//char szInfo[100];
		//sprintf(szInfo, "%p room:%u", pClient, pClient->GetRoomID());
		//ZDEBUG(szInfo);

		_U64 rid = pClient->GetRoomID();
		if(rid == ROOM_ID_INVAILD)
		{
			pClient->Lobby.LeaveRoomResult(RET_CODE_LEAVE_ROOM_INVAILD);
			return;
		}

		Atlas::CObjectLocker<Atlas::CRoomInfo> Locker(rid);
		CRoomInfo* pRoom = Locker.GetObject();
		if(!pRoom)
		{
			pClient->Lobby.LeaveRoomResult(RET_CODE_LEAVE_ROOM_INVAILD);
			return;
		}

		pRoom->DelClient(pClient);

		pClient->Lobby.LeaveRoomResult(RET_CODE_SUCC);
	}

	void GameMgr::SendMsg( CExLobbyAvatarNodeClient* pClient,  const char* szMsg)
	{
		_U64 rid = pClient->GetRoomID();
		if(rid == ROOM_ID_INVAILD)
		{
			return;
		}

		Atlas::CObjectLocker<Atlas::CRoomInfo> Locker(rid);
		CRoomInfo* pRoom = Locker.GetObject();
		pRoom->SetExistState(false);
		std::set<CExLobbyAvatarNodeClient*> clients = pRoom->GetClients();
		for(std::set<CExLobbyAvatarNodeClient*>::iterator it = clients.begin();
			it != clients.end(); ++it)
		{
			(*it)->Lobby.ReceiveMessage(szMsg);
		}
	}

	void GameMgr::CreateRoom( CExLobbyAvatarNodeClient* pClient, const char* name )
	{
		_U64 rid = pClient->GetRoomID();
		if(rid != ROOM_ID_INVAILD)
		{
			pClient->Lobby.CreateRoomResult(ROOM_ID_INVAILD);
			return;
		}

		rid = _global_room_object_manager.Alloc();
		
		A_MUTEX_LOCK(&m_RoomLock);
		CRoomInfo* pRoom = CreateRoomInfo(rid);
		A_MUTEX_UNLOCK(&m_RoomLock);
		pRoom->AddClient(pClient);

		_global_room_object_manager.Unlock(rid);
		
		//char szInfo[100];
		//sprintf(szInfo, "%p room:%u", pClient, pClient->GetRoomID());
		//ZDEBUG(szInfo);

		pClient->Lobby.CreateRoomResult(rid);
	}

	CRoomInfo* GameMgr::CreateRoomInfo(_U64 ndx)
	{
		ROOM_INFO room;
		room.name = "room";
		room.id = ndx;
		CRoomInfo* pRoom = ATLAS_NEW CRoomInfo(room, ndx);
		_global_rooms[ndx] = pRoom;
		return pRoom;
	}

}